﻿using System;
using System.Collections.Generic;

namespace Allegro.Mathlib
{
    public class NormalRandom : IRandom
    {
        private IRandom _uniformRandom;
        private int _iset = 0;
        private double _gset;
        private int _seed;
        private double _v1, _v2;
        private double _rsq;
        private bool _set;

        public NormalRandom()
            : this(DateTime.Now.GetHashCode())
        {
        }
        public NormalRandom(int seed)
        {
            _seed = seed;
            _uniformRandom = new UniformRandom(seed);
            //_uniformRandom = new UniformRandom2(seed);
            _set = false;
            //_Reinit();
        }

        void _Reinit()
        {
            do
            {
                // We don't have an extra deviate handy, so pick two uniform numers in the square extending
                // from -1 to +1 in each direction
                _v1 = 2.0 * _uniformRandom.DrawOne() - 1.0;
                _v2 = 2.0 * _uniformRandom.DrawOne() - 1.0;
                _rsq = _v1 * _v1 + _v2 * _v2;
            }
            while (_rsq >= 1.0 || _rsq == 0.0);
            _set = true;
        }
        public double DrawOne()
        {
            double random;
            // Now make the Box-Muller transformation to get two normal deviates. 
            // Return one and save the other for next time.
            if (!_set)
            {
                _Reinit();
                double fac = Math.Sqrt(-2.0 * Math.Log(_rsq) / _rsq);
                _gset = _v1 * fac;
                _set = true;
                random = _v2*fac;
            }
            else
            {
                _set = false;
                random = _gset;
            }

            return random;
        }

        public double[] DrawMany(int n)
        {
            double[] samples = new double[n];
            for (int i = 0; i < n; i++)
            {
                samples[i] = DrawOne();
            }
            return samples;
        }
    }
}
